#ifndef SEU_PEER_H
#define SEU_PEER_H
#include"include.h"

/* This file defines peer structures
 * and should give the prototype for
 * all peer wire transport stuff.
 * This is the peer-communication stuff
 * in other words.
 */

typedef struct {
   unsigned int ndx;
   unsigned int offset;
   unsigned int len;
} piece_request;

typedef struct peer_struct {
   unsigned char my_interest;
   unsigned char peer_interest;
   unsigned char my_choking;
   unsigned char peer_choking;
   unsigned int last_choke; //For optimistick anti-snubbing
   unsigned int peer_alive; //Drop the connection if this hits 3 mins
   unsigned int my_alive;   //Send a keep-alive if this hits 1 mins
   bitfield_t *bitfield; //bools for have/don't have
   dict_t *activeReqs; //Key is ndx, value is bitfield
   unsigned int my_reqs;
   unsigned int pieceLength;

   list_t *requestList; //Will be used like a quue.
   
   // Communication info
   int socket_descriptor;
   unsigned short port; // Port and IP only filled in if we make the connection
   unsigned int ip;
   char peer_id[20];
   unsigned short ready;
} peer_t;

// Generic torrent message structure
typedef struct {
   uint32_t len_prefix;
   unsigned char message_ID;
   void *payload;
} netmsg_t;

/* Peer Messaging */
// Message IDs
#define KEEPALIVE     0
#define CHOKE         0
#define UNCHOKE       1
#define INTERESTED    2
#define NOTINTERESTED 3
#define HAVE          4
#define BITFIELD      5
#define REQUEST       6
#define PIECE         7
#define CANCEL        8
#define PORT          9

/* All peer outgoing messaging functions expect the peer_t structure to have an
 * initialized and connected socket_descriptor.
 * 
 * Each function returns 0 upon successfully sent message, 1 if some error
 * occured.
 *
 * Refer to the BitTorrent specifications for further information on the
 * function and parameters of these functions.
 */

// Handshakes someone and expects a response
int peerHandshake(peer_t *p, char *peer_id, unsigned char info_hash[20]);
// Handshakes and does not expect a response. This should only be done in
// in response to a handshake
int sendHandshake(int sock, char *peer_id, unsigned char info_hash[20]);

int peerSendKeepAlive(peer_t *p);
int peerSendChoke(peer_t *p);
int peerSendUnchoke(peer_t *p);
int peerSendInterested(peer_t *p);
int peerSendNotInterested(peer_t *p);
int peerSendHave(peer_t *p, uint32_t bid);
int peerSendBitfield(peer_t *p, bitfield_t *bitfield);
int peerSendRequest(peer_t *p, uint32_t ndx, uint32_t begin,
   uint32_t len);
int peerSendPiece(peer_t *p, uint32_t ndx, uint32_t begin,
   unsigned char *block, int block_len);
int peerSendCancel(peer_t *p, uint32_t ndx, uint32_t begin,
   uint32_t len);
int peerSendPort(peer_t *p, uint16_t listen_port);

#define CHECK_WAIT_TIME 50
#define SOCK_ERR 1
#define NOT_EMPTY 2
#define PEER_SHUTDOWN 3
/* A non-blocking function that checks to see if a peer has sent any messages.
 *
 * If a message has been received, the callback is called with the oldest
 * message.
 *
 * If any sort of socket IO error occurs, this function returns SOCK_ERR; if 
 * there are still messages waiting to be parsed, it returns NOT_EMPTY; 
 * otherwise, it returns 0.
 */
int peerCheckRecieved(peer_t *p, void *torrent, void (*callback) (void *torrent, peer_t *, netmsg_t));

// Peer management
peer_t *peerInit(unsigned long torrent_len, unsigned int len);
void peerDisconnect(peer_t *p);
void peerPrint(peer_t *p);

//The non-networking peer stuff for keeping track of bitfields etc.
void peerSetHave(peer_t *p, unsigned int ndx);
int peerGetHave(peer_t *p, unsigned int ndx);
void peerSetBitfield(peer_t *p, unsigned int len, unsigned char *field);
void peerSetRequest(peer_t *p, unsigned int ndx, unsigned int offset, unsigned int len);
int peerRequested(peer_t *p, unsigned int ndx, unsigned int offset);
void peerCancelRequest(peer_t *p, unsigned int ndx, unsigned int offset, unsigned int len);



#endif
